package com.homelock;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubboConfig;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.hibernate.validator.HibernateValidator;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.homelock.filter.AccessRecorderFilter;

@SpringBootApplication
@MapperScan(basePackages={"com.pi", "com.homelock.mapper"})
@ComponentScan({"com.pi", "com.homelock"})
//@PropertySource("classpath:config.properties")
@EnableDubbo
public class HomeLockApplication {
  @Value("${server.port}")
  private int HTTPS_PORT;
  @Value("${server.http.port}")
  private int HTTP_PORT;
  public static ApplicationContext CONTEXT = null;
  private static final Logger logger = LoggerFactory.getLogger(HomeLockApplication.class);
	@Bean //手动初始化DruidDataSource 对象
	@ConfigurationProperties(prefix = "spring.datasource")
	public DataSource druid(){
		DruidDataSource ds = new DruidDataSource();
		return ds;
	}
			
	//注册后台界面Servlet bean , 用于显示后台界面
	@Bean
	public ServletRegistrationBean statViewServlet(){
		//创建StatViewServlet，绑定到/druid/路径下
		//开启后，访问localhost/druid就可以看到druid管理后台
		ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet() , "/druid/*");
		Map<String ,String > param = new HashMap<String,String>();
		param.put("loginUsername" , "admin");
		param.put("loginPassword" , "aA12346");
		param.put("allow" , "");//哪些IP允许访问后台“”代表所有地址
		param.put("deny" , "33.31.51.88");//不允许这个IP访问
		bean.setInitParameters(param);
		return bean;
	}

	//用于监听获取应用的数据 ， Filter用于收集数据, Servlet用于展现数据
	@Bean
	public FilterRegistrationBean webStatFilter(){
		FilterRegistrationBean bean = new FilterRegistrationBean();
		bean.setFilter(new WebStatFilter()); //设置过滤器
		bean.addUrlPatterns("/*");
		Map<String,String> param = new HashMap<String,String>();
		//排除静态资源
		param.put("exclusions" , "*.png,*.woff,*.js,*.css,/druid/*");
		bean.setInitParameters(param);
		return bean;
	}
	
	//在入口类中注册Filter
	@Bean //@Bean会将方法中的返回对象在SpringBoot启动的时候放入IOC容器
	public FilterRegistrationBean filterRegiste(){
		FilterRegistrationBean regFilter = new FilterRegistrationBean();
		//创建并注册AccessRecorderFilter
		regFilter.setFilter(new AccessRecorderFilter());
		//对所有请求进行拦截
		regFilter.addUrlPatterns("/*");
		//过滤器名字
		regFilter.setName("AccessRecorder");
		//设置排序,如果系统中有多个过滤器,order就决定了那个过滤器先执行，数字越小越靠前执行
		regFilter.setOrder(1);
		return regFilter;
	}
	
    public static void main(String[] args) {

//    {@link org.springframework.boot.context.event.ApplicationStartingEvent} springboot启动开始时执行的事件
//    {@link org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent}spring boot 对应Enviroment已经准备完毕，但此时上下文context还没有创建。
//    {@link org.springframework.boot.context.event.ApplicationFailedEvent} spring boot启动异常时执行事件 
    SpringApplication application = new SpringApplication(HomeLockApplication.class);
    application.addListeners((ApplicationListener<ApplicationEnvironmentPreparedEvent>) event -> {
      logger.info("----------------- Spring 环境首次初始化成功：{} -----------------------------");
    });
    application.addListeners((ApplicationListener<ApplicationStartingEvent>) event -> {
      logger.info("----------------- Spring Boot 应用正在启动：{} -----------------------------");
    });
    application.addListeners((ApplicationListener<ApplicationReadyEvent>) event -> {
      
    });
    application.addListeners((ApplicationListener<ApplicationFailedEvent>) event -> {
      logger.info("----------------- Spring Boot应用启动失败：" + event.getException().toString());
    });
    CONTEXT = 
        application.run(args);
    }
    
    
    @Bean
    public ConfigurableServletWebServerFactory servletContainer() {
      TomcatServletWebServerFactory  tomcat = new TomcatServletWebServerFactory () {
          @Override
          protected void postProcessContext(Context context) {
              SecurityConstraint constraint = new SecurityConstraint();
              constraint.setUserConstraint("NONE");//CONFIDENTIAL
              SecurityCollection collection = new SecurityCollection();
              collection.addPattern("/*");
              constraint.addCollection(collection);
              context.addConstraint(constraint);
          }
      };
      tomcat.addAdditionalTomcatConnectors(httpConnector());
      return tomcat;
    }

//    配置文件配置了https端口,这里配置http端口
    @Bean
    public Connector httpConnector() {
      Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
      connector.setScheme("https");
      connector.setPort(HTTP_PORT);
      connector.setSecure(false);
      connector.setRedirectPort(HTTPS_PORT);
      return connector;
    }
    
//    配置validator为快速验证(因为默认会返回所有错误消息，这个是没必要的)
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure().failFast(true)
//                .addProperty("hibernate.validator.fail_fast", "true")
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();
        return validator;
    }
}